﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ElfTyping.States.GameState.PlayerSpells;
using ElfTyping.States.GameState.PlayerPassives;

namespace ElfTyping.Cards
{
    public class CardManager
    {
        const int Arrow_CardChance = 5;
        const int Spell_CardChance = 7;
        const int Passive_CardChance = 8;

        const int Booster_CardCount = 5;

        private Dictionary<string, SpellCard> SpellCardMap = new Dictionary<string, SpellCard>()
        {
            {"SPELL-HEAL", new SpellCard(new HealSpell())},
            {"SPELL-ELFIRE", new SpellCard(new ElfireSpell())},
        };

        private Dictionary<string, PassiveCard> PassiveCardMap = new Dictionary<string, PassiveCard>()
        {
            {"PASSIVE-DOUBLESHOT", new PassiveCard(new DoubleShotPassive())},
            {"PASSIVE-FROSTARROW", new PassiveCard(new FrostArrowPassive())},
        };

        private Dictionary<string, HaremCard> HaremCardMap = new Dictionary<string,HaremCard>()
        {
            {"HAREM-DEMON", new HaremCard(HaremType.Demon)},
            {"HAREM-ELF", new HaremCard(HaremType.Elf)},
            {"HAREM-TAN", new HaremCard(HaremType.Tan)},
            {"HAREM-White", new HaremCard(HaremType.White)}
        };

        private Dictionary<string, int> CardCountMap = new Dictionary<string, int>();

        private Random random = new Random();

        private static CardManager _singleton = null;
        public static CardManager GetManager()
        {
            if (_singleton == null)
            {
                _singleton = new CardManager();
            }

            return _singleton;
        }

        private CardManager()
        {
            foreach (var card in SpellCardMap)
            {
                card.Value.ID = card.Key;
            }

            foreach (var card in PassiveCardMap)
            {
                card.Value.ID = card.Key;
            }

            foreach (var card in HaremCardMap)
            {
                card.Value.ID = card.Key;
            }
        }

        private static int[] ArrowCardCumulativeChances = { 0, 60, 80, 92, 100};

        private Card GenerateRandomCard()
        {
            int rand = random.Next(1,101);
            if (rand <= Arrow_CardChance)
            {
                int arrowRand = random.Next(1, 101);
                for (int i = 0; i < ArrowCardCumulativeChances.Length; i++)
                {
                    if (arrowRand <= ArrowCardCumulativeChances[i])
                    {
                        return new ArrowCard(i);
                    }
                }
            }
            else if (rand <= Arrow_CardChance + Spell_CardChance)
            {
                var idAndCard = SpellCardMap.OrderBy(pair => random.Next()).First();
                idAndCard.Value.ID = idAndCard.Key;
                return idAndCard.Value;
            }
            else if (rand <= Arrow_CardChance + Spell_CardChance + Passive_CardChance)
            {
                var idAndCard = PassiveCardMap.OrderBy(pair => random.Next()).First();
                idAndCard.Value.ID = idAndCard.Key;
                return idAndCard.Value;
            }
            else
            {
                return new HaremCard();
            }

            return null;
        }

        public List<Card> GenerateBooster()
        {
            List<Card> result = new List<Card>();
            for (int i = 0; i < Booster_CardCount; i++)
            {
                result.Add(GenerateRandomCard());
            }
            return result;
        }

        public Card GetCardWithID(string id)
        {
            if (id.StartsWith("ARROW"))
            {
                return new ArrowCard(int.Parse(id.Split('-')[1]));
            }
            else if (PassiveCardMap.ContainsKey(id))
            {
                return PassiveCardMap[id];
            }
            else if (SpellCardMap.ContainsKey(id))
            {
                return SpellCardMap[id];
            }
            else if (HaremCardMap.ContainsKey(id))
            {
                return HaremCardMap[id];
            }

            return null;
        }

        public void FoundCard(Card card)
        {
            if (CardCountMap.ContainsKey(card.ID))
            {
                CardCountMap[card.ID] = CardCountMap[card.ID] + 1;
            }
            else
            {
                CardCountMap[card.ID] = 1;
            }
        }

        public void FoundBooster(List<Card> booster)
        {
            foreach (Card card in booster)
            {
                FoundCard(card);
            }
        }

        public Dictionary<SpellCard, int> GetSpellOnlyCount()
        {
            Dictionary<SpellCard, int> result = new Dictionary<SpellCard, int>();
            foreach (KeyValuePair<string, SpellCard> spell in SpellCardMap)
            {
                if (CardCountMap.ContainsKey(spell.Key))
                {
                    result.Add(spell.Value, CardCountMap[spell.Key]);
                }
            }

            return result;
        }

        public Dictionary<PassiveCard, int> GetPassiveOnlyCount()
        {
            Dictionary<PassiveCard, int> result = new Dictionary<PassiveCard, int>();
            foreach (KeyValuePair<string, PassiveCard> passive in PassiveCardMap)
            {
                if (CardCountMap.ContainsKey(passive.Key))
                {
                    result.Add(passive.Value, CardCountMap[passive.Key]);
                }
            }

            return result;
        }

        public Dictionary<ArrowCard, int> GetArrowOnlyCount()
        {
            Dictionary<ArrowCard, int> result = new Dictionary<ArrowCard, int>();
            for (int damage = 1; damage <= ArrowCard.Arrow_MaxDamage; damage++)
            {
                ArrowCard card = new ArrowCard(damage);
                if (CardCountMap.ContainsKey(card.ID))
                {
                    result.Add(card, CardCountMap[card.ID]);
                }
            }

            return result;
        }

        public List<string> SerializeToList()
        {
            List<string> result = new List<string>();

            foreach (KeyValuePair<string, int> cardCount in CardCountMap)
            {
                for (int i=0; i<cardCount.Value; i++) {
                    result.Add(cardCount.Key);
                }
            }

            return result;
        }

        public void DeserializeFromList(List<string> list)
        {
            CardCountMap = new Dictionary<string, int>();

            foreach (string card in list)
            {
                if (CardCountMap.ContainsKey(card))
                {
                    CardCountMap[card] = CardCountMap[card] + 1;
                }
                else
                {
                    CardCountMap[card] = 1;
                }                
            }
        }
    }
}
